package com.zrq.gencode;

import com.zrq.gencode.cfg.GenCfg;
import com.zrq.gencode.domain.classdata.ClassBase;
import com.zrq.gencode.domain.tabledata.TableBase;
import com.zrq.gencode.jdbc.ConnectionPool;
import com.zrq.gencode.jdbc.CreateTable;
import com.zrq.gencode.jdbc.DataTable;
import com.zrq.gencode.util.Comvlt;
import com.zrq.gencode.util.Velocity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 代码生成器主应用程序
 *
 * @author ZRQ
 */
public class GenCodeApplication {
	private static final Logger logger = LoggerFactory.getLogger(GenCodeApplication.class);
	private static final String BEAN = "Entity";

	/**
	 * 程序入口
	 */
	public static void run() {
		logger.info("开始执行代码生成任务");
		long start = System.currentTimeMillis();

		try {
			// 测试数据库连接
			logger.info("测试数据库连接...");
			if (!ConnectionPool.testConnection()) {
				logger.error("数据库连接测试失败，请检查数据库配置");
				return;
			}
			logger.info("数据库连接测试成功");

			logger.info("获取数据库表信息中...");
			// 尝试执行SQL脚本
			try {
				CreateTable.implementSql();
			} catch (Exception e) {
				logger.warn("执行SQL脚本时出错，继续执行代码生成: {}", e.getMessage());
			}

			// 获取表信息
			List<ClassBase> classBases = getJavaBaseList();

			// 检查是否获取到表信息
			if (classBases.isEmpty()) {
				logger.warn("未获取到任何数据库表信息，程序退出");
				return;
			}

			logger.info("准备生成 {} 个类的代码", classBases.size());

			// 根据配置决定是否使用多线程模式
			if (GenCfg.enableMultithreading) {
				logger.info("使用多线程模式进行代码生成中...");
				// 使用多线程执行代码生成任务
				executeCodeGenerationInParallel(classBases);
			} else {
				logger.info("使用单线程模式进行代码生成中...");
				// 使用单线程执行代码生成任务
				executeCodeGenerationSequentially(classBases);
			}

			logger.info("代码生成完成，耗时: {}ms", System.currentTimeMillis() - start);
		} catch (Exception e) {
			logger.error("代码生成过程中发生错误", e);
			throw e;
		} finally {
			ConnectionPool.closeDataSource();
		}
	}

	/**
	 * 使用多线程执行代码生成任务
	 *
	 * @param classBases 类信息列表
	 */
	private static void executeCodeGenerationInParallel(List<ClassBase> classBases) {
		// 手动创建线程池，提供更好的控制和资源管理
		int corePoolSize = Runtime.getRuntime()
			.availableProcessors();
		int maximumPoolSize = corePoolSize * 2;
		long keepAliveTime = 60L;
		ExecutorService executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
		                                                  TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000),
		                                                  new ThreadPoolExecutor.CallerRunsPolicy());

		// 使用原子计数器跟踪成功生成的类数量
		AtomicInteger successCount = new AtomicInteger(0);
		AtomicInteger errorCount = new AtomicInteger(0);

		for (ClassBase classBase : classBases) {
			executor.submit(() -> {
				try {
					creatEntity(classBase);
					creatService(classBase);
					creatServiceImpl(classBase);
					creatDao(classBase);
					creatWeb(classBase);
					successCount.incrementAndGet();
				} catch (Exception e) {
					errorCount.incrementAndGet();
					logger.error("生成类 {} 的代码时发生错误", classBase.getClassName(), e);
				}
			});
		}

		// 关闭线程池并等待所有任务完成
		executor.shutdown();
		try {
			// 等待所有任务完成，最多等待配置的分钟数
			if (!executor.awaitTermination(GenCfg.threadPoolTimeoutMinutes, TimeUnit.MINUTES)) {
				executor.shutdownNow();
				logger.warn("代码生成任务超时，强制终止");
			} else {
				logger.info("所有代码生成任务已完成，成功生成 {} 个类，失败 {} 个", successCount.get(), errorCount.get());
			}
		} catch (InterruptedException e) {
			executor.shutdownNow();
			Thread.currentThread()
				.interrupt();
			logger.error("等待代码生成任务完成时被中断", e);
		}
	}

	/**
	 * 使用单线程顺序执行代码生成任务
	 *
	 * @param classBases 类信息列表
	 */
	private static void executeCodeGenerationSequentially(List<ClassBase> classBases) {
		int successCount = 0;
		int errorCount = 0;
		for (ClassBase classBase : classBases) {
			try {
				creatEntity(classBase);
				creatDao(classBase);
				if (classBase.getHasId()) {
					creatService(classBase);
					creatServiceImpl(classBase);
					creatWeb(classBase);
				}
				successCount++;
			} catch (Exception e) {
				errorCount++;
				logger.error("生成类 {} 的代码时发生错误", classBase.getClassName(), e);
			}
		}
		logger.info("代码生成完成，成功生成 {} 个类，失败 {} 个", successCount, errorCount);
	}

	/**
	 * 创建实体类
	 */
	private static void creatEntity(ClassBase classBase) {
		Velocity.done(Comvlt.ENTITY_VM,
		              (GenCfg.getEntity() + Comvlt.SLASH + classBase.getClassName()).replace(Comvlt.POIT,
		                                                                                     Comvlt.SLASH) + Comvlt.JAVA,
		              classBase);
	}

	/**
	 * 创建业务接口类
	 */
	private static void creatService(ClassBase classBase) {
		Velocity.done(Comvlt.SERVICE_VM, (GenCfg.getService() + Comvlt.SLASH + GenCfg.serviceName.replace(BEAN,
		                                                                                                  classBase.getClassName())).replace(
			Comvlt.POIT, Comvlt.SLASH) + Comvlt.JAVA, classBase);
	}

	/**
	 * 创建业务实现类
	 *
	 * @param classBase 类信息
	 */
	private static void creatServiceImpl(ClassBase classBase) {
		Velocity.done(Comvlt.SERVICEIMPL_VM, (GenCfg.getServiceimpl() + Comvlt.SLASH + GenCfg.serviceImplName.replace(
			BEAN, classBase.getClassName())).replace(Comvlt.POIT, Comvlt.SLASH) + Comvlt.JAVA, classBase);
	}

	/**
	 * 创建控制类
	 *
	 * @param classBase 类信息
	 */
	private static void creatWeb(ClassBase classBase) {
		Velocity.done(Comvlt.WEB_VM, (GenCfg.getWeb() + Comvlt.SLASH + GenCfg.controllerName.replace(BEAN,
		                                                                                             classBase.getClassName())).replace(
			Comvlt.POIT, Comvlt.SLASH) + Comvlt.JAVA, classBase);
	}

	/**
	 * 创建持久化类
	 *
	 * @param classBase 类信息
	 */
	private static void creatDao(ClassBase classBase) {
		Velocity.done(Comvlt.DAO_VM, (GenCfg.getDao() + Comvlt.SLASH + GenCfg.daoName.replace(BEAN,
		                                                                                      classBase.getClassName())).replace(
			Comvlt.POIT, Comvlt.SLASH) + Comvlt.JAVA, classBase);
	}

	/**
	 * 获取创建所需信息
	 *
	 * @return List<ClassBase>
	 */
	private static List<ClassBase> getJavaBaseList() {
		List<TableBase> tables = new ArrayList<>();
		List<String> tableNames = DataTable.getTableNames();

		// 检查是否获取到表名
		if (tableNames.isEmpty()) {
			logger.warn("未获取到任何数据库表名");
			return new ArrayList<>();
		}

		logger.info("获取到 {} 个表名", tableNames.size());

		for (String tableName : tableNames) {
			TableBase table = new TableBase();
			table.setTableName(tableName);
			table.setColumnBases(DataTable.getColumns(tableName));
			tables.add(table);
		}
		return Comvlt.crovTableToJava(tables.toArray(new TableBase[0]));
	}
}